import java.awt.Image;
import java.awt.Graphics;
import java.awt.Event;
import java.awt.Color;
import java.awt.Dimension;
import java.applet.Applet;
import java.util.Random;

public class springs extends Applet implements Runnable
{

        Image buffer;
        Graphics bufferG;
        Thread t;

/* gravity acceleration */
public static double  G = -9.8;

/* mass */
public static double  M = 10.0;

/* spring parameter in Hook's law */
public static double K = 50.0;

/* velocity damping parameter */
public static double K2 = 1.0;

/* time slice */
public static double DT = 0.1;

/* Replusion between nodes */
public static double R = 10.0; 



myVector ball[], F_ball[], d_ball[], dd_ball[]; 
myVector old_ball[], old_d_ball[]; 

int width, height;

public void init_balls()
{
        int i;
   for (i = 0; i < 7; i++)
        ball[i].init();
   for (i = 0; i < 7; i++)
        F_ball[i].init();
   for (i = 0; i < 7; i++)
        d_ball[i].init();
   for (i = 0; i < 7; i++)
        dd_ball[i].init();
   for (i = 0; i < 7; i++)
        old_ball[i].init();
   for (i = 0; i < 7; i++)
        old_d_ball[i].init();


   //fix first ball
   ball[0].x =100;
   ball[0].y = 100;

   //fix last ball
   ball[6].x = width - 100;
   ball[6].y = 100;


   //initialize moving balls
   for (i=1; i<6; i++)
        {
        ball[i].x = myRandom.getRandom(width);
        ball[i].y = myRandom.getRandom(height);
        }

}

public void init () 
{
   int i;
   Dimension d = this.size();
   width = d.width;
   height = d.height;

   ball = new myVector[7];
   for (i = 0; i < 7; i++)
        ball[i] = new myVector();
   F_ball = new myVector[7];
   for (i = 0; i < 7; i++)
        F_ball[i] = new myVector();
   d_ball = new myVector[7];
   for (i = 0; i < 7; i++)
        d_ball[i] = new myVector();
   dd_ball = new myVector[7];
   for (i = 0; i < 7; i++)
        dd_ball[i] = new myVector();
   old_ball = new myVector[7];
   for (i = 0; i < 7; i++)
        old_ball[i] = new myVector();
   old_d_ball = new myVector[7];
   for (i = 0; i < 7; i++)
        old_d_ball[i] = new myVector();

   buffer = createImage(width, height);
   bufferG = buffer.getGraphics();




   init_balls();

}

public void run()
{
   int i;

   while (true)
        {
        //clear image here
        bufferG.clearRect(0, 0, width, height);

        /* draw springs */
        for (i=0; i<6; i++)
        {
        bufferG.setColor(Color.blue);
        bufferG.drawLine((int)ball[i].x, (int)ball[i].y,
                (int)ball[i+1].x, (int)ball[i+1].y);
        }




        /* draw all the nodes (cirlce points) */
        for (i=0; i<7; i++)
        {
                bufferG.setColor(Color.red);
                bufferG.fillOval((int)ball[i].x - 5, (int)ball[i].y - 5, 10,10);
        }


        repaint(); 
        /* calculate forces on each nodes */
        recalculate_ball_position();
        try
        {
        Thread.sleep(10);
        }
        catch(Exception e)
        {
        System.out.println("Exception: " + e);
        }

  }


}

public boolean handleEvent(Event e)
{
        if (e.id == Event.MOUSE_DOWN)
                {
                init_balls();
                }
        return false;
}

public void paint(Graphics g)
{
        //draw buffered image to screen
        g.drawImage(buffer, 0, 0, this);

}

void recalculate_ball_position()
{
        int i;
    for (i=1; i<6; i++) { 
      F_ball[i].x = - K*(2*ball[i].x - ball[i+1].x - ball[i-1].x)
				    - K2*d_ball[i].x;
      F_ball[i].y = - K*(2*ball[i].y - ball[i+1].y - ball[i-1].y)
				    - K2*d_ball[i].y - M*G;
    }

	/* calculate the new position of each nodes */
    for (i=1; i<6; i++) {

	  /* accelerations */
      dd_ball[i].x = F_ball[i].x / M;
      dd_ball[i].y = F_ball[i].y / M;

	  /* velocities */
      d_ball[i].x =  old_d_ball[i].x + dd_ball[i].x*DT;
      d_ball[i].y =  old_d_ball[i].y + dd_ball[i].y*DT;

	  /* positions */
      ball[i].x =  old_ball[i].x + d_ball[i].x*DT;
      ball[i].y =  old_ball[i].y + d_ball[i].y*DT;

      old_d_ball[i].x = d_ball[i].x;
      old_d_ball[i].y = d_ball[i].y;

      old_ball[i].x = ball[i].x;
      old_ball[i].y = ball[i].y;
      }

}

//override update method to cut down on flicker
public void update(Graphics g)
{
        paint(g);
}
public void start()
{
        if (t == null)
        {
                t = new Thread(this);
                t.start();

        }
}

public void stop()
{
        if (t != null)
        {
                t.stop();
                t = null;
        }
}


}


class myVector
{
        double x;
        double y;
        public void init()
        {
                x = y = 0.0;
        }
}

class myRandom
{
        static Random rand = new Random();

        static int getRandom(int low, int high)
        {
                int range = high - low;
                float rfactor = rand.nextFloat();
                int random = (int) (range * rfactor);


                int retval = low + random;
                return retval;
        }

        static int getRandom(int high)
        {
                return getRandom(0, high);
        }

        public static void main(String[] argv)
        {
                for (int i = 0; i < 100; i++)
                        {
                        System.out.println(getRandom(10));
                        }
        }

}
